package com.lmaye.handler;

import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;
import com.lmaye.App;
import com.lmaye.common.BaseResponse;
import com.lmaye.common.ErrorInfo;
import com.lmaye.retrying.RequestRetryListener;
import com.lmaye.utils.*;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Response;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * -- 服务应用检测健康监控 Handler
 * <pre>
 * - 1. 登陆接口;
 * - 2. 查询用户钱包资产列表;
 * - 3. 查询我的比特宝总收益及总资产;
 * - 注: 每个接口重试3次，如果还是失败则发送短信通知;
 * </pre>
 *
 * @author lmay.Zhou
 * @date 2019/6/6 15:19 星期四
 * @qq 379839355
 * @email lmay@lmaye.com
 */
@Slf4j
public class DetectRequestHandler {
    /**
     * 通用Http请求
     *
     * @param requestUrl 请求地址
     * @param method     请求方法
     * @param mediaType  数据类型
     * @param params     请求参数苏
     * @return BaseResponse
     * @throws Exception 异常
     */
    @SuppressWarnings({"unchecked", "ConstantConditions", "Guava", "Duplicates"})
    private static BaseResponse request(String requestUrl, Method method, MediaType mediaType, Map<String, Object> params)
            throws Exception {
        Callable<BaseResponse> callable = () -> {
            // 请求参数配置
            OKHttpConfig config = OKHttpConfig.builder().url(requestUrl).headers(null)
                    .method(method).mediaType(mediaType).params(params).build();
            // 执行请求
            Response response = OkHttpUtils.execute(config);
            byte[] bytes = response.body().bytes();
            String result = new String(bytes);
            log.info("[{}] result: {}", requestUrl, result);
            return GsonUtils.fromJson(result, BaseResponse.class);
        };
        Map<String, Object> appProperties = App.APP_PROPERTIES;
        Map<String, Integer> retryingProperties = (Map<String, Integer>) appProperties.get("retrying");
        // 定义重试机制
        Retryer<BaseResponse> retryer = RetryerBuilder.<BaseResponse>newBuilder()
                // 响应码不是000000重试
                .retryIfResult(cmsResultDTO -> !Objects.equals(cmsResultDTO.getCode(), "000000"))
                // 响应数据为null重试
                .retryIfResult(cmsResultDTO -> Objects.isNull(cmsResultDTO.getData()))
                // 返回的数据是null重试
                .retryIfResult(Predicates.<BaseResponse>isNull())
                // 返回的异常
                .retryIfExceptionOfType(Exception.class)
                // 重调策略(重调次数)
                .withStopStrategy(StopStrategies.stopAfterAttempt(retryingProperties.get("retryTimes")))
                // 隔10秒重试
                .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
                // 监听器
                .withRetryListener(new RequestRetryListener<BaseResponse>())
                .build();
        return retryer.call(callable);
    }

    /**
     * 登陆
     *
     * @param requestUrl 请求地址
     * @param username   用户名
     * @param password   密码
     * @return BaseResponse
     */
    public static BaseResponse login(String requestUrl, String username, String password) {
        BaseResponse baseResponse;
        try {
            Map<String, Object> params = new HashMap<>(3);
            params.put("account", username);
            params.put("password", password);
            params.put("source", "1");
            baseResponse = request(requestUrl, Method.POST, MediaType.FORM, params);
        } catch (Exception e) {
            log.error("{} - 请求处理失败: {}", requestUrl, e);
            baseResponse = BaseResponse.failed(ErrorInfo.error());
        }
        return baseResponse;
    }

    /**
     * 查询用户钱包资产列表
     *
     * @param requestUrl 请求地址
     * @param token      token
     * @return BaseResponse
     */
    public static BaseResponse userCapitalTotal(String requestUrl, String token) {
        BaseResponse baseResponse;
        try {
            Map<String, Object> params = new HashMap<>(1);
            params.put("type", "2");
            params.put("token", token);
            // 请求参数配置
            baseResponse = request(requestUrl, Method.POST, MediaType.FORM, params);
        } catch (Exception e) {
            log.error("{} - 请求处理失败: {}", requestUrl, e);
            baseResponse = BaseResponse.failed(ErrorInfo.error());
        }
        return baseResponse;
    }

    /**
     * 查询我的比特宝总收益及总资产
     *
     * @param requestUrl 请求地址
     * @param token      token
     * @return BaseResponse
     */
    public static BaseResponse checkingEarningsTotal(String requestUrl, String token) {
        BaseResponse baseResponse;
        try {
            Map<String, Object> params = new HashMap<>(1);
            params.put("token", token);
            // 请求参数配置
            baseResponse = request(requestUrl, Method.POST, MediaType.FORM, params);
        } catch (Exception e) {
            log.error("{} - 请求处理失败: {}", requestUrl, e);
            baseResponse = BaseResponse.failed(ErrorInfo.error());
        }
        return baseResponse;
    }
}
